 /*******************************************************************************
  * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/

 package org.eclipse.ui.internal.intro.impl.model.util;

 import java.io.IOException ;
 import java.net.URL ;

 import org.eclipse.core.runtime.FileLocator;
 import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProduct;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.ui.internal.intro.impl.util.Log;
 import org.eclipse.ui.internal.intro.impl.util.StringUtil;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;

 /**
  * Bundle convenience methods.
  */
 public class BundleUtil {

     private static String NL_TAG = "$nl$/"; //$NON-NLS-1$
 private final static String PRODUCT_PLUGIN = "PRODUCT_PLUGIN"; //$NON-NLS-1$
 private final static String PLUGINS_ROOT = "PLUGINS_ROOT/"; //$NON-NLS-1$

     /**
      * Utility method to validate the state of a bundle. Log invalid bundles to
      * log file.
      */
     public static boolean bundleHasValidState(Bundle bundle) {
         if (bundle == null || bundle.getState() == Bundle.UNINSTALLED
                 || bundle.getState() == Bundle.INSTALLED) {

             if (bundle == null)
                 Log.error("Intro tried accessing a NULL bundle.", null); //$NON-NLS-1$
 else {
                 String msg = StringUtil
                     .concat("Intro tried accessing Bundle: ", getBundleHeader( //$NON-NLS-1$
 bundle, Constants.BUNDLE_NAME), " vendor: ", //$NON-NLS-1$
 getBundleHeader(bundle, Constants.BUNDLE_VENDOR),
                         " bundle state: ", String.valueOf(bundle.getState())).toString(); //$NON-NLS-1$
 Log.error(msg, null);
             }
             return false;
         }

         return true;
     }

     /**
      * Retrieves the given key from the bundle header.
      *
      * @param bundle
      * @param key
      * @return
      */
     public static String getBundleHeader(Bundle bundle, String key) {
         return (String ) bundle.getHeaders().get(key);
     }


     public static Bundle getBundleFromConfigurationElement(
             IConfigurationElement cfg) {
         return Platform.getBundle(cfg.getContributor().getName());
     }


     /**
      * Get the resourcelocation, but do not force an $nl$ on it.
      *
      * @param resource
      * @param element
      * @return
      */
     public static String getResourceLocation(String resource,
             IConfigurationElement element) {
         Bundle bundle = getBundleFromConfigurationElement(element);
         return getResolvedResourceLocation(resource, bundle, false);
     }


     /**
      * Returns the fully qualified location of the passed resource string from
      * the passed plugin id. If the file could not be loaded from the plugin,
      * the resource is returned as is.
      *
      * @param resource
      * @return
      */
     public static String getResolvedResourceLocation(String resource,
             String pluginId) {
         Bundle bundle = Platform.getBundle(pluginId);
         return getResolvedResourceLocation(resource, bundle, true);
     }


     /**
      * Shorthand util method.
      *
      * @param resource
      * @return
      */
     public static String getResolvedResourceLocation(String resource,
             Bundle bundle) {
         return getResolvedResourceLocation(resource, bundle, true);
     }


     public static String getResolvedResourceLocation(String base,
             String resource, Bundle bundle) {
         // quick exits.
 if (resource == null)
             return null;

         String fullResource = new Path(base).append(resource).toString();
         String resolvedResource = getResolvedResourceLocation(fullResource,
             bundle, true);

         if (resolvedResource.equals(fullResource))
             // return resource as is when the resource does not exist.
 return resource;
         return resolvedResource;
     }


     public static String getResolvedResourceLocation(String resource,
             Bundle bundle, boolean forceNLResolve) {
         // quick exits.
 if (resource == null)
             return null;

         if (bundle == null || !bundleHasValidState(bundle))
             return resource;

         URL localLocation = null;
         try {
             // resolve PLUGINS_ROOT
 int index = resource.indexOf(PLUGINS_ROOT);
             if (index != -1) {
                 resource = resource.substring(index + PLUGINS_ROOT.length());
                 index = resource.indexOf('/');
                 if (index != -1) {
                     String bundleName = resource.substring(0, index);
                     if (PRODUCT_PLUGIN.equals(bundleName)) {
                         IProduct product = Platform.getProduct();
                         if (product != null) {
                             Bundle productBundle = product.getDefiningBundle();
                             if (productBundle != null) {
                                 bundleName = productBundle.getSymbolicName();
                             }
                         }
                     }
                     resource = resource.substring(index + 1);
                     Bundle actualBundle = Platform.getBundle(bundleName);
                     if (actualBundle != null) {
                         return getResolvedResourceLocation(resource, actualBundle, forceNLResolve);
                     }
                 }
             }
             
             // we need to resolve this URL.
 String copyResource = resource;
             if (forceNLResolve && !copyResource.startsWith(NL_TAG)) {
                 if (copyResource.startsWith("/") //$NON-NLS-1$
 || copyResource.startsWith("\\")) //$NON-NLS-1$
 copyResource = resource.substring(1);
                 copyResource = NL_TAG + copyResource;
             }
             IPath resourcePath = new Path(copyResource);
             localLocation = FileLocator.find(bundle, resourcePath, null);
             if (localLocation == null) {
                 // localLocation can be null if the passed resource could not
 // be found relative to the plugin. log fact, return resource,
 // as is.
 String msg = StringUtil.concat("Could not find resource: ", //$NON-NLS-1$
 resource, " in ", getBundleHeader( //$NON-NLS-1$
 bundle, Constants.BUNDLE_NAME)).toString();
                 Log.warning(msg);
                 return resource;
             }
             /*
             localLocation = FileLocator.toFileURL(localLocation);
             return localLocation.toExternalForm();
             */
             return toExternalForm(localLocation);
         } catch (Exception e) {
             String msg = StringUtil.concat("Failed to load resource: ", //$NON-NLS-1$
 resource, " from ", getBundleHeader(bundle, //$NON-NLS-1$
 Constants.BUNDLE_NAME)).toString();
             Log.error(msg, e);
             return resource;
         }
     }




     /** *** used by Intro parser ***** */
     /*
      * Util method to return an URL to a plugin relative resource.
      */
     public static URL getResourceAsURL(String resource, String pluginId) {
         Bundle bundle = Platform.getBundle(pluginId);
         URL localLocation = FileLocator.find(bundle, new Path(
             resource), null);
         return localLocation;
     }




     /** ********************* Used by HTML generator ****************** */
     /**
      * Get the absolute path of the given bundle, in the form
      * file:/path_to_plugin
      *
      * @param bundle
      * @return
      */
     public static String getResolvedBundleLocation(Bundle bundle) {
         try {
             URL bundleLocation = bundle.getEntry(""); //$NON-NLS-1$
 if (bundleLocation == null)
                 return null;
             /*
             bundleLocation = FileLocator.toFileURL(bundleLocation);
             return bundleLocation.toExternalForm();
             */
             return toExternalForm(bundleLocation);
         } catch (IllegalStateException e) {
             Log.error("Failed to access bundle: " //$NON-NLS-1$
 + bundle.getSymbolicName(), e);
             return null;
         }/* catch (IOException e) {
             Log.error("Failed to resolve URL path for bundle: " //$NON-NLS-1$
                     + bundle.getSymbolicName(), e);
             return null;
         } */
     }

     /**
      * Get the absolute path of the bundle with id <code>bundleId</code>. If
      * no such bundle is found, return null.
      *
      * @param bundleId
      * @return
      */
     public static String getResolvedBundleLocation(String bundleId) {
         Bundle bundle = Platform.getBundle(bundleId);
         if (bundle == null)
             return null;
         return getResolvedBundleLocation(bundle);
     }
     
     /*
      * Bug 126085 - need to fix up file: protocol
      * to a form that IE7 understands (file:///).
      */
     
     private static String toExternalForm(URL localURL) {
         try {
             localURL = FileLocator.toFileURL(localURL);
             String result = localURL.toExternalForm();
             if (result.startsWith("file:/")) { //$NON-NLS-1$
 if (result.startsWith("file:///")==false) { //$NON-NLS-1$
 result = "file:///"+result.substring(6); //$NON-NLS-1$
 }
             }
             return result;
         }
         catch (IOException e) {
             String msg = "Failed to resolve URL: " //$NON-NLS-1$
 + localURL.toString();
                 Log.error(msg, e);
                 return localURL.toString();
         }
     }

 }

